<?php
class CDbConnectionManager extends CApplicationComponent {
	/**
	 * 主数据连接
	 * @var Array CDbConnection
	 */
	private static $_masters = array();
	
	/**
	 * 从数据库连接
	 * @var Array CDbConnection
	 */
	private static $_slaves = array();
	
	/**
	 * 当前的数据库连接配置
	 * @var Array
	 */
	private $_config = array();
	
	/**
	 * 分库键值
	 * 根据该值确定所要连接的数据库
	 * @var String
	 */
	private $_dbKey = '';
	
	/**
	 * 分表键值
	 * 根据该值确定表名称
	 * @var String
	 */
	private $_tableKey = '';
	
	/**
	 * 所有的数据库连接配置
	 * @var Array
	 */
	public $connectionConfig = array();
	
	/**
	 * 分库方式
	 * 对应 CShardedMethod 类中的 方法名
	 * @var String 
	 */
	public $dbShardedMethod = '';
	
	/**
	 * 分表方式
	 * 对应 CShardedMethod 类中的 方法名
	 * @var String 
	 */
	public $tableShardedMethod = '';
	
	/**
	 * 通用的数据库连接用户
	 * @var String
	 */
	public $username = '';
	
	/**
	 * 通用的数据库连接密码
	 * @var String
	 */
	public $password = '';
	
	/**
	 * 通用的数据字符集
	 * @var String
	 */
	public $charset = 'utf8';
	
	/**
	 * 是否启用从库连接
	 * @var bool $enableSlave 
	 */
	public $enableSlave = true;
	
	/**
	 * 获取数据库连接
	 *
	 * @param Boolean $isMaster 是否为主库链接，默认为 true
	 * @return CDbConnection
	 */
	public function getDbConnection($isMaster = true) {
		return $isMaster ? $this->getMasterDbConnection() : $this->getSlaveDbConnection();
	}
	
	/**
	 * 获取主库连接
	 * 
	 * @return CDbConnection
	 */
	protected function getMasterDbConnection() {
		$key = md5($this->_config['connectionString']);
		if(!array_key_exists($key, self::$_masters)) {
			$master = $this->createDbConnection($this->_config);
			$master->enableSlave = $this->enableSlave;
			
			self::$_masters[$key] = $master;
		}
		return self::$_masters[$key];
	}
	
	/**
	 * 获取从库连接
	 * 
	 * @return CDbConnection
	 */
	protected function getSlaveDbConnection() {
		$key = $this->_dbKey;
		
		if(!array_key_exists($key, self::$_slaves)) {
			$slavesConfig = $this->_config['slaves'];
			
			shuffle($slavesConfig['connectionStrings']);
			$slavesConfig['connectionString'] = $slavesConfig['connectionStrings'][0];
			
			$slave = $this->createDbConnection($slavesConfig);
			$slave->active = true;
			$slave->enableSlave = false;
			Yii::trace('Opened slave DB connection.', __METHOD__.':'.__LINE__);
			
			self::$_slaves[$key] = $slave;
		}
		
		return self::$_slaves[$key];
	}
	
	/**
	 * 设置分库分表键值
	 */
	public function sharded($value) {
		$shardedModel = CShardedMethod::model();
		
		if(!$shardedModel->exists($this->dbShardedMethod)) throw new CDbException('DB sharded method is not exists!');
		if(!$shardedModel->exists($this->tableShardedMethod)) throw new CDbException('Table sharded method is not exists!');
		
		$this->_dbKey = $shardedModel->{$this->dbShardedMethod}($value);
		if(!array_key_exists($this->_dbKey, $this->connectionConfig)) throw new CDbException('Invalid sharded method or value!');
		
		$this->_config = $this->connectionConfig[$this->_dbKey];
		$this->_tableKey = $shardedModel->{$this->tableShardedMethod}($value);
		
		Yii::trace(sprintf('dbKey: %s, tableKey: %s', $this->_dbKey, $this->_tableKey), __METHOD__.':'.__LINE__);
		return $this;
	}
	
	/**
	 * 获取分表键值
	 */
	public function getShardedTableKey() {
		return $this->_tableKey;
	}
	
	/**
	 * 获取分库键值
	 */
	public function getShardedDbKey() {
		return $this->_dbKey;
	}
	
	/**
	 * @return dbConnection->createCommand
	 */
	public function createCommand($sql = null) {
		return $this->dbConnection->createCommand($sql);
	}
	
	/**
	 * 通过数据库配置创建数据库连接
	 * 
	 * @param Array $config
	 * @return CDbConnection
	 */
	protected function createDbConnection($config) {
		!isset($config['charset']) && $config['charset'] = $this->charset;
		!isset($config['username']) && $config['username'] = $this->username;
		!isset($config['password']) && $config['password'] = $this->password;
		
		$config['connectionString'] .= sprintf('charset=%s;', $config['charset']);
		
		Yii::trace('Create DB connection: '.$config['connectionString'], __METHOD__.':'.__LINE__);
		
		$connection = new CDbConnectionMasterSlave($config['connectionString'], $config['username'], $config['password']);
		return $connection;
	}
}